/*
MIT License 

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов, 

https://bmstu.codes/lsx/simodo
*/

#ifndef simodo_token_Scanner
#define simodo_token_Scanner

/*! \file Scanner.h
    \brief Сканер входного потока
*/

#include "simodo/inout/token/Token.h"
#include "simodo/inout/token/InputStream_interface.h"

#include <string>
#include <istream>


namespace simodo::inout
{
    /*!
     * \brief Поддержка сканирования текста.
     *
     * Содержит характеристики местоположения и методы для сравнения текущего текста с лексическими
     * примитивами при работе Tokenizer.
     */
     
    class Scanner
    {
        uri_index_t             _uri_index;
        InputStream_interface & _input;             ///< Входной поток
        context_index_t         _context_index;
        std::u16string          _buffer;                    ///< Текущий буфер разбора примитивов
        position_line_t         _current_line;              ///< Номер строки (с единицы)
        position_character_t    _current_character;         ///< Позиция в строке (с единицы)
        bool                    _is_end_of_file_reached;    ///< Признак достижения спец. символа конца файла
        position_line_t         _token_start_line = 0;      ///< Номер строки (с единицы)
        position_character_t    _token_start_character = 0; ///< Позиция в строке (с единицы)
        context_index_t         _token_context_index = NO_TOKEN_CONTEXT_INDEX;

    protected:
        /*!
         * \brief Перемещает один код теста из входного потока в буфер
         * \return true, если код был перемещён и false, если достигнут конец потока
         */
        bool    putCharToBuffer();

    public:
        Scanner() = delete; ///< Без инициализации параметров не имеет смысла

        /*!
         * \brief Конструктор сканера входного потока
         *
         * \param file_name     Имя файла
         * \param input_stream  Входной поток
         * \param tab_size      Размер табуляции
         * \param context_index Номер контекста начала разбора (используется при подсветке синтаксиса)
         */
        Scanner(uri_index_t uri_index, InputStream_interface & input_stream,
                context_index_t context_index=NO_TOKEN_CONTEXT_INDEX);

        context_index_t context() const { return _context_index; }

        /*!
         * \brief eof
         * \return true, если достигнут конец потока, иначе - false
         */
        bool eof() const { return (_buffer.empty() && (_is_end_of_file_reached || _input.eof())); }

        /*!
         * \brief setEOF
         */
        void    setEOF() { _is_end_of_file_reached = true; }

        /*!
         * \brief Сдвиг входного потока на заданное количество текстовых символов
         * \param length   Величина сдвига
         * \return true, если сдвиг произошёл и false, если достигнут конец потока
         *
         * \attention   Величина сдвига не должна превышать количество символов во внутреннем буфере.
         *              Т.е. ожидается, что сдвиг будет выполняться с проанализованным текстом.
         */
        bool    shift(size_t length);

        /*!
         * \brief Возвращает текущее состояние обработки токена
         * \return Текущее состояние обработки токена после последнего вызова shift
         */
        TokenLocation makeTokenLocation() const;

        /*!
         * \brief Запоминает текущее состояние обработки входного потока как начало токена
         * \param context_index Текущий контекст обработки маркированного токена
         */
        void    fixLocation(context_index_t context_index=NO_TOKEN_CONTEXT_INDEX);

        /*!
         * \brief Сравнение кода текстового символа с первым символом текущего состояния потока
         * \param ch   Код текстового символа, которую нужно сравнить
         * \return true, если код текстового символа совпадает с текущим содержимым потока
         */
        bool    startsWith(char16_t ch);

        /*!
         * \brief Сравнение строки с началом текущего состояния потока
         * \param str   Строка, которую нужно сравнить
         * \return true, если заданная строка совпадает с текущим содержимым потока
         */
        bool    startsWith(const std::u16string & str);

        /*!
         * \brief Проверка на содержание текущего символа входного потока в заданной строке
         * \param str   Строка символов, которые нужно проверить
         * \return true, если текущий символ содержится в заданной строке
         */
        bool    startsWithAnyOf(const std::u16string & str);

        /*!
         * \brief Получение текущего символа входного потока
         * \return Текущий символ входного потока
         */
        char16_t getFirstChar(void);


        char16_t getChar(size_t pos = 0);
    };
}

#endif // simodo_token_Scanner
